/**
 * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package slcu.service.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.liferay.portal.kernel.dao.orm.DynamicQuery;
import com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil;
import com.liferay.portal.kernel.dao.orm.OrderFactoryUtil;
import com.liferay.portal.kernel.dao.orm.ProjectionFactoryUtil;
import com.liferay.portal.kernel.dao.orm.ProjectionList;
import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
import com.liferay.portal.kernel.dao.orm.Session;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.OrderByComparatorFactoryUtil;
import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
import com.liferay.portal.kernel.util.StringComparator;
import com.liferay.portal.model.User;

import slcu.DeportistaAlreadyApprovedException;
import slcu.DeportistaAlreadyEnabledException;
import slcu.DeportistaAlreadyRegisteredException;
import slcu.NoSuchDeportistaException;
import slcu.inscripcion.InscripcionStatus;
import slcu.model.Alumno;
import slcu.model.Deportista;
import slcu.model.Equipo;
import slcu.model.Escuela;
import slcu.model.Inscripcion;
import slcu.model.impl.DeportistaImpl;
import slcu.service.DeportistaLocalServiceUtil;
import slcu.service.base.DeportistaLocalServiceBaseImpl;
import slcu.service.persistence.DeportistaPersistenceImpl;
import slcu.service.persistence.DeportistaUtil;
import slcu.service.persistence.EquipoUtil;
import slcu.service.persistence.EscuelaUtil;
import slcu.service.persistence.InscripcionUtil;

/**
 * The implementation of the Deportista local service.
 *
 * <p>
 * All custom service methods should be put in this class. Whenever methods are added, rerun ServiceBuilder to copy their definitions into the {@link slcu.service.DeportistaLocalService} interface.
 *
 * <p>
 * This is a local service. Methods of this service will not have security checks based on the propagated JAAS credentials because this service can only be accessed from within the same VM.
 * </p>
 *
 * @author Pablo Carballo
 * @see slcu.service.base.DeportistaLocalServiceBaseImpl
 * @see slcu.service.DeportistaLocalServiceUtil
 */
public class DeportistaLocalServiceImpl extends DeportistaLocalServiceBaseImpl {
	/*
	 * NOTE FOR DEVELOPERS:
	 *
	 * Never reference this interface directly. Always use {@link slcu.service.DeportistaLocalServiceUtil} to access the Deportista local service.
	 */
	
	private static Log _log = LogFactoryUtil.getLog(DeportistaLocalServiceImpl.class);
	
	public Deportista insertarDeportista(Deportista deportista, User user)
			throws SystemException, PortalException {		

		List<Deportista> deportistas = deportistaPersistence.findByDNI(deportista.getDni());
		Deportista deportistaExistente = deportistas.size() > 0 ? deportistas.get(0) : null;

		if (deportistaExistente != null) {
			throw new DeportistaAlreadyRegisteredException(
					"El alumno ya se encuentra inscripto, DNI: " +
					deportista.getDni());			
		}

		Deportista newDeportista = createDeportista(
				counterLocalService.increment(Deportista.class.getName()));

		newDeportista.setDni(deportista.getDni());
		newDeportista.setNombres(deportista.getNombres());
		newDeportista.setApellido(deportista.getApellido());
		newDeportista.setMail(deportista.getMail());
		newDeportista.setEscuelaId(deportista.getEscuelaId());
		newDeportista.setFecha_nacimiento(deportista.getFecha_nacimiento());
		newDeportista.setCompanyId(user.getCompanyId());
		newDeportista.setGroupId(user.getGroupId());
		newDeportista.setInscripcionStatus(0);
		newDeportista.setInscripcionStatusPrevApproved(false);
		newDeportista.setInscripcionStatusByUserId(user.getUserId());
		newDeportista.setInscripcionStatusByUserName(user.getFullName());
		newDeportista.setInscripcionStatusDate(new Date());
		newDeportista.setNivel(deportista.getNivel());

		return updateDeportista(newDeportista, true);
	}

	
	public Deportista registrarDeportista(Alumno alumno, User user, boolean prevApproved, boolean dejarPendiente) 
			throws SystemException, PortalException {		

		List<Deportista> deportistas = deportistaPersistence.findByDNI(alumno.getDni());
		Deportista deportista = deportistas.size() > 0 ? deportistas.get(0) : null;  
		Boolean exists = deportista != null;
		Boolean isAdded = exists && deportista.getInscripcionStatus() == InscripcionStatus.STATUS_ADDED;
		Integer registerStatus = dejarPendiente ? InscripcionStatus.STATUS_REGISTERED : InscripcionStatus.STATUS_ADDED;
		
		Boolean alreadyRegisteredError = exists && dejarPendiente && !isAdded;		
		if (alreadyRegisteredError) {
			throw new DeportistaAlreadyRegisteredException(
						"El deportista ya se encuentra registrado, DNI: " + alumno.getDni());				
		}
		
		Boolean keepSame = exists && !dejarPendiente;
		if (keepSame) {
			return deportista;
		}

		Deportista newDeportista;
		if (isAdded) {
			newDeportista = deportista;
		} else {
			newDeportista = createDeportista(
				counterLocalService.increment(Deportista.class.getName()));
		}
		
		newDeportista.setDni(alumno.getDni());
		newDeportista.setNombres(alumno.getNombres());
		newDeportista.setApellido(alumno.getApellido());
		newDeportista.setEscuelaId(alumno.getEscuelaId());
		newDeportista.setFecha_nacimiento(alumno.getFecha_nacimiento());
		newDeportista.setCompanyId(user.getCompanyId());
		newDeportista.setGroupId(user.getGroupId());		
		newDeportista.setInscripcionStatus(registerStatus);
		newDeportista.setInscripcionStatusPrevApproved(prevApproved);
		newDeportista.setInscripcionStatusByUserId(user.getUserId());
		newDeportista.setInscripcionStatusByUserName(user.getFullName());
		newDeportista.setInscripcionStatusDate(new Date());

		return updateDeportista(newDeportista, true);
	}
	
	public Deportista desregistrarDeportista(Deportista deportista, User user) throws SystemException {
		
		return deportistaPersistence.remove(deportista);
		
	}
	
	public Deportista habilitarDeportista(Deportista deportista, User user) 
			throws SystemException, NoSuchDeportistaException, DeportistaAlreadyEnabledException {

		if (deportista.getInscripcionStatus() == InscripcionStatus.STATUS_ENABLED) {
			throw new DeportistaAlreadyEnabledException(String.format(
					"El deportista ya se encuentra habilitado, DNI %s", deportista.getDni()));
		}
		
		deportista.setInscripcionStatus(InscripcionStatus.STATUS_ENABLED);
		deportista.setInscripcionStatusByUserId(user.getUserId());
		deportista.setInscripcionStatusByUserName(user.getFullName());
		deportista.setInscripcionStatusDate(new Date());
		
		return deportistaPersistence.update(deportista, true);
	
	}
	
	public Deportista rechazarDeportista(Deportista deportista, String comment, User user) 
			throws PortalException, SystemException {
		
		deportista.setInscripcionStatus(InscripcionStatus.STATUS_REJECTED);
		deportista.setInscripcionStatusByUserId(user.getUserId());
		deportista.setInscripcionStatusByUserName(user.getFullName());
		deportista.setInscripcionStatusDate(new Date());
		deportista.setInscripcionStatusComment(comment);
		
		return deportistaPersistence.update(deportista, true);		
				
	}
	
	/*
	 * Coordinador Vuelve a pendiente un deportista Habilitado o Rechazado (Deshace la acci��n previa)
	 * @see slcu.service.DeportistaLocalService#volverAPendiente(slcu.model.Deportista, com.liferay.portal.model.User)
	 */
	public Deportista volverAPendiente(Deportista deportista, User user) throws DeportistaAlreadyApprovedException, PortalException, SystemException {
		
		int statusActual = deportista.getInscripcionStatus(); 
		
		if (statusActual != InscripcionStatus.STATUS_ENABLED && 
			statusActual != InscripcionStatus.STATUS_REJECTED) {
			throw new PortalException(
					"La inscripcion del deportista no " + 
					"fue habilitada ni rechazada, DNI " + deportista.getDni());
		}
		
		deportista.setInscripcionStatus(InscripcionStatus.STATUS_REGISTERED);
		deportista.setInscripcionStatusByUserId(user.getUserId());
		deportista.setInscripcionStatusByUserName(user.getFullName());
		deportista.setInscripcionStatusDate(new Date());
		deportista.setInscripcionStatusComment("");
		
		return deportistaPersistence.update(deportista, true);
		
	}
	
	/*
	 * Profesor vuelve a registrar un deportista Rechazado para revision
	 * @see slcu.service.DeportistaLocalService#volverARegistrar(slcu.model.Deportista, com.liferay.portal.model.User)
	 */
	public Deportista volverARegistrar(Deportista deportista, String comment, User user) throws DeportistaAlreadyApprovedException, PortalException, SystemException {
		
		deportista.setInscripcionStatus(InscripcionStatus.STATUS_REGISTERED);
		deportista.setInscripcionStatusByUserId(user.getUserId());
		deportista.setInscripcionStatusByUserName(user.getFullName());
		deportista.setInscripcionStatusDate(new Date());
		deportista.setInscripcionStatusComment(comment);
		
		return deportistaPersistence.update(deportista, true);
		
	}
	
	public boolean estaRechazado(String dni) throws SystemException {
		
		Deportista deportista = deportistaPersistence.fetchByDNI_First(dni, null);
		return (deportista != null && 
				deportista.getInscripcionStatus() == InscripcionStatus.STATUS_REJECTED);
		
	}
	
	// Start Finders
	
	public Deportista getFirstByDNI(String dni) throws NoSuchDeportistaException, SystemException {

		Deportista deportista = deportistaPersistence.fetchByDNI_First(dni, null);

		if (deportista == null) {
			throw new NoSuchDeportistaException("No se encuentra el deportista con DNI " + dni);
		}
		
		return deportista;
		
	}
	
	public List<Deportista> findByInscripcionUserId(long userId, int start, int end) throws SystemException {
		
		DynamicQuery query = DynamicQueryFactoryUtil.forClass(Deportista.class);
		query.add(PropertyFactoryUtil.forName("inscripcionStatusByUserId")
                .eq(userId));
		
		query.addOrder(OrderFactoryUtil.desc("inscripcionStatusDate"));		
	
		return DeportistaUtil.findWithDynamicQuery(query, start, end);
		
	}
	
	public int countByInscripcionUserId(long userId) throws SystemException {
	
		return DeportistaUtil.countByinscripcionUserId(userId);
	
	}
	
	private DynamicQuery createDynamicQueryFromMap(Map<String, String> map, boolean count) {

		DynamicQuery query = DynamicQueryFactoryUtil.forClass(Deportista.class);

		if (map.get("dniOrNombresOrApellido") != null && !map.get("dniOrNombresOrApellido").trim().equals(""))
			query.add(RestrictionsFactoryUtil.or(
					RestrictionsFactoryUtil.or(
					PropertyFactoryUtil.forName("dni").like("%" + map.get("dniOrNombresOrApellido").trim() + "%"),
					PropertyFactoryUtil.forName("nombres").like("%" + map.get("dniOrNombresOrApellido").trim() + "%")),
					PropertyFactoryUtil.forName("apellido").like("%" + map.get("dniOrNombresOrApellido").trim() + "%")));
		
		try {			
			if (map.get("fechaNacimientoMinima") != null && !map.get("fechaNacimientoMinima").trim().equals(""))
				query.add(PropertyFactoryUtil.forName("fecha_nacimiento")
						.le(new SimpleDateFormat("dd/MM/yyyy").parse(map.get("fechaNacimientoMinima").trim())));
		} catch (ParseException e) {			
		}

		try {
			if (map.get("fechaNacimientoMaxima") != null && !map.get("fechaNacimientoMaxima").trim().equals(""))
				query.add(PropertyFactoryUtil.forName("fecha_nacimiento")
						.ge(new SimpleDateFormat("dd/MM/yyyy").parse(map.get("fechaNacimientoMaxima").trim())));
		} catch (ParseException e) {
		}
		
		try {
			if (map.get("escuelaId") != null && !map.get("escuelaId").trim().equals(""))
				query.add(PropertyFactoryUtil.forName("escuelaId")
						.eq(Long.valueOf(map.get("escuelaId").trim())));
		}
		catch (Exception e) {
			_log.error("Error filtrando por escuelaId: " + 
					   map.get("escuelaId"));
		}
		
		if (map.get("dni") != null && !map.get("dni").trim().equals(""))
			query.add(PropertyFactoryUtil.forName("dni")
					.like("%" + map.get("dni").trim() + "%"));
		
		if (map.get("nombre") != null && !map.get("nombre").trim().equals(""))
			query.add(PropertyFactoryUtil.forName("nombre")
					.like("%" + map.get("nombre").trim() + "%"));
		
		if (map.get("~inscripcionStatus") != null && !map.get("~inscripcionStatus").trim().equals("")) {
			
			String notStatusString = map.get("~inscripcionStatus").trim();
			try {
				Integer notStatus = Integer.valueOf(notStatusString);
				query.add(PropertyFactoryUtil.forName("inscripcionStatus")
						  .ne(notStatus));
			} catch (NumberFormatException e) {
				_log.warn("El valor de ~inscripcionStatus no es un n��mero v��lido: " + notStatusString);				
			}			
		}

		try {
			if (map.get("region") != null && !map.get("region").trim().equals("")) {
				
				List<Escuela> escuelas = EscuelaUtil.findByRegion(map.get("region").trim());
				Collection<Object> escuelaIds = new ArrayList<Object>();				
				for (Escuela escuela: escuelas) {
					escuelaIds.add(escuela.getPrimaryKey());
				}
				
				query.add(PropertyFactoryUtil.forName("escuelaId").in(escuelaIds));
				
			}
		} catch (Exception e) {
			_log.error("Error filtrando por region: " + 
					   map.get("region"));
		} 
		
		try {
			if (map.get("inscripcionStatusByUserId") != null && !map.get("inscripcionStatusByUserId").trim().equals("")) {
				Long inscripcionStatusByUserId = Long.valueOf(map.get("inscripcionStatusByUserId").trim());
				query.add(PropertyFactoryUtil.forName("inscripcionStatusByUserId")
						.eq(inscripcionStatusByUserId));
			}
		} catch (Exception e) {
			_log.error("Error filtrando por inscripcionStatusByUserId: " + 
					   map.get("inscripcionStatusByUserId"));
		}		
		
		try {
			String inscripcionStatus = map.get("inscripcionStatus");
			if (inscripcionStatus != null && !inscripcionStatus.isEmpty()) {
				Integer inscripcionStatusId = Integer.valueOf(inscripcionStatus.trim());
				query.add(PropertyFactoryUtil.forName("inscripcionStatus")
						.eq(inscripcionStatusId));
			}
		} catch (Exception e) {
			_log.error("Error filtrando por inscripcionStatus: " + 
					   map.get("inscripcionStatus"));
		}
		
		try {
			String preAprobado = map.get("preAprobado");
			if (preAprobado != null && !preAprobado.isEmpty()) {
				if (preAprobado.equals("true")) {
					query.add(PropertyFactoryUtil.forName("inscripcionStatusPrevApproved").eq(Boolean.TRUE));
				} else if (preAprobado.equals("false")) {
					query.add(PropertyFactoryUtil.forName("inscripcionStatusPrevApproved").eq(Boolean.FALSE));
				}
			}
		} catch (Exception e) {
			_log.error("Error filtrando por preAprobado: " + 
					   map.get("preAprobado"));
		} 

		if (!count && map.get("orderBy") != null && !map.get("orderBy").trim().equals("")) {
			if (map.get("orderType") != null && map.get("orderType").trim().equals("desc"))
				query.addOrder(OrderFactoryUtil.desc(map.get("orderBy")));
			else
				query.addOrder(OrderFactoryUtil.asc(map.get("orderBy")));
		}

		return query;

	}

	public List<Deportista> findByMap(Map<String, String> map) throws SystemException {

		DynamicQuery query = createDynamicQueryFromMap(map, false);

		return DeportistaUtil.findWithDynamicQuery(query);

	}

	public List<Deportista> findByMap(Map<String, String> map, int start, int end) throws SystemException {

		DynamicQuery query = createDynamicQueryFromMap(map, false);

		return DeportistaUtil.findWithDynamicQuery(query, start, end);

	}

	public long countByMap(Map<String, String> map) throws SystemException {

		DynamicQuery query = createDynamicQueryFromMap(map, true);

		return new DeportistaUtil().countWithDynamicQuery(query);

	}
	
	private DynamicQuery queryByEscuelaEstado(long escuelaId, int inscripcionStatus) {
		DynamicQuery query = DynamicQueryFactoryUtil.forClass(Deportista.class);
		query.add(PropertyFactoryUtil.forName("escuelaId").eq(escuelaId))
             .add(PropertyFactoryUtil.forName("inscripcionStatus").eq(inscripcionStatus));
		
		query.addOrder(OrderFactoryUtil.desc("inscripcionStatusDate"));
		
		return query;
	}
	
	public List<Deportista> findByEscuelaEstado(long escuelaId, int inscripcionStatus, int start, int end) throws SystemException {
		DynamicQuery query = queryByEscuelaEstado(escuelaId, inscripcionStatus);
		return DeportistaUtil.findWithDynamicQuery(query, start, end);  
	}
	
	public long countByEscuelaEstado(long escuelaId, int inscripcionStatus) throws SystemException {
		DynamicQuery query = queryByEscuelaEstado(escuelaId, inscripcionStatus);
		return new DeportistaUtil().countWithDynamicQuery(query);
	}
	
	private DynamicQuery queryByRegionEstado(String region, int inscripcionStatus) throws SystemException {
		
		List<Escuela> escuelas = EscuelaUtil.findByRegion(region);
		Collection<Object> escuelaIds = new ArrayList<Object>();
		
		for (Escuela escuela: escuelas) {
			escuelaIds.add(escuela.getPrimaryKey());
		}
		
		DynamicQuery query = DynamicQueryFactoryUtil.forClass(Deportista.class);
		query.add(PropertyFactoryUtil.forName("escuelaId").in(escuelaIds))
             .add(PropertyFactoryUtil.forName("inscripcionStatus").eq(inscripcionStatus));
		
		query.addOrder(OrderFactoryUtil.desc("inscripcionStatusDate"));
		
		return query;
	}
	
	public List<Deportista> findByRegionEstado(String region, int inscripcionStatus, int start, int end) throws SystemException {
		DynamicQuery query = queryByRegionEstado(region, inscripcionStatus);
		return DeportistaUtil.findWithDynamicQuery(query, start, end);  
	}
	
	public long countByRegionEstado(String region, int inscripcionStatus) throws SystemException {
		DynamicQuery query = queryByRegionEstado(region, inscripcionStatus);
		return new DeportistaUtil().countWithDynamicQuery(query);
	}
	
	public void countEscuelaEstadoByRegion(String region)  {
		ProjectionList plist = ProjectionFactoryUtil.projectionList();  
		plist.add(ProjectionFactoryUtil.groupProperty("escuelaId"));
		plist.add(ProjectionFactoryUtil.groupProperty("inscripcionStatus"));
		plist.add(ProjectionFactoryUtil.rowCount(), "_count");  
		  
		DynamicQuery query = DynamicQueryFactoryUtil.forClass(Deportista.class)		
		 .setProjection(plist);
		
		List results = null;
		try {
		   results = DeportistaLocalServiceUtil.dynamicQuery(query);
		} catch (SystemException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		Integer escuelaId, inscripcionStatus, count = 5;				
		for (Object rowObj : results) {
		    Object row[] = (Object[]) rowObj;
		    System.out.println("Escuela " + row[0].toString());
		    System.out.println("Status " + row[1].toString());
		    System.out.println("Count " + row[2].toString());
		    System.out.println("-----");

			/*
		    escuelaId = (Integer) row[0];
		    inscripcionStatus = (Integer) row[1];
		    count = (Integer) row[2];		 
		    System.out.println(escuelaId + ", " + inscripcionStatus + ", " + count);
		    */
		}
		
	}
	
	public List<Deportista> filterByCategoriaId(List<Deportista> listDeportistas, long categoriaId){
		
		List<Deportista> listDeportistaFiltrada = new LinkedList<Deportista>();
		
		for (Deportista deportista : listDeportistas) {
			try {
				List<Inscripcion> listInscripcion = InscripcionUtil.findByDeportistaId(deportista.getDeportistaId());
				for (Inscripcion inscripcion : listInscripcion) {
					Equipo equipo = EquipoUtil.fetchByPrimaryKey(inscripcion.getEquipoId());
					if(equipo != null && equipo.getCategoriaId() == categoriaId)
						listDeportistaFiltrada.add(deportista);		
				}
			} catch (SystemException e) {
				_log.error("Error filtrando por categoria");			   
				e.printStackTrace();}
			
		}
		return listDeportistaFiltrada;
		
	}

}
